/*
 * Peripheral Simulator (PSim)
 *
 * Copyright (c) 2008 Avadh Patel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "sim_cpu.h"
#include "psim.h"

static SimCPU* sim_cpu;
static SimDevice* sim_cpu_dev;
static int sim_cpu_uuid;

int sim_cpu_io_read(uint32_t addr, uint32_t *data, int size, void* opaque)
{
  //find the destination device, if its simulated then only continue
  SimDevice* dev = sim_find_dev_with_addr(addr, size);
  if(dev == NULL)
    return -1;

  //set no_return flag
  sim_cpu->no_return = 1;
  sim_set_no_return();
  //Create a Message
  Message* msg = sim_new_read_msg(opaque, addr, size);
//  msg->from = sim_get_dev_by_id(sim_cpu_uuid);
  msg->from = sim_cpu_dev;
  sim_insert_cb(sim_get_bridge()->in, msg, 1);
  sim_do_callback();
  
  //when the simulation comes back msg contains the data
  *data = msg->data;
  sim_delete_message(msg);
  return 0;
}

int sim_cpu_io_write(uint32_t addr, uint32_t data, int size, void* opaque)
{
  //find the destination device, if its simulated then only continue
  SimDevice* dev = sim_find_dev_with_addr(addr, size);
  if(dev == NULL)
    return -1;

  //set no_return flag
  sim_cpu->no_return = 1;
  sim_set_no_return();
  //Create a Message
  Message* msg = sim_new_write_msg(opaque, addr, data, size);
//  msg->from = sim_get_dev_by_id(sim_cpu_uuid);
  msg->from = sim_cpu_dev;
  sim_insert_cb(sim_get_bridge()->in, msg, 1);
  sim_do_callback();
  
  sim_delete_message(msg);
  return 0;
}

void sim_cpu_in(Message* in_msg)
{
//  assert(data!=NULL);
//  Message* in_msg = (Message*)data;
  int i = sim_get_no_return();
  if(i) {
    sim_reset_no_return();
//    sim_delete_message(in_msg);
//    free(in_msg);
  }
}

void sim_cpu_init()
{
  sim_cpu = malloc(sizeof(SimCPU));
//  sim_cpu_uuid = sim_register_device(CPU, "CPU1", sim_cpu, 0xff0, 4, 4, 0); 
  sim_cpu_dev = sim_register_device(CPU, "CPU1", NULL, 0);
  sim_register_qemu_device(sim_cpu_dev, sim_cpu);
  sim_register_addr(sim_cpu_dev, 0xff0,4,4);
  sim_register_in_cb(sim_cpu_dev, &sim_cpu_in);
}
